package com.demo.gateway.sentinel.filter;

import com.demo.gateway.sentinel.config.SysConstatnt;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.UUID;
import java.util.function.Supplier;

/**
 * 链路追踪filter
 * 模拟返回前修改header内容
 */
@Configuration
@Slf4j
public class TraceFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 允许接入traceid
        String traceIdVal = request.getHeaders().getFirst(SysConstatnt.TRACE_ID);
        if(StringUtils.isEmpty(traceIdVal)) {
            traceIdVal = UUID.randomUUID().toString();
            log.info("生成新的traceId:{}",traceIdVal);
        }else {
            log.warn("请求传入包含traceId:{}，可能引发日志中traceId不准确",traceIdVal);
        }
        // 写入log mdc
        MDC.put(SysConstatnt.TRACE_ID, traceIdVal);
        // 向后传递
        request = request.mutate().header(SysConstatnt.TRACE_ID, traceIdVal).build();
        // 继续处理请求链路
        String finalTraceIdVal = traceIdVal;
        /*exchange = exchange.mutate().request(request).response(new ServerHttpResponseDecorator(exchange.getResponse()){
            // 响应处理
            @Override
            public void beforeCommit(Supplier<? extends Mono<Void>> action) {
                if(!response.getHeaders().containsKey(SysConstatnt.TRACE_ID)) {
                    response.getHeaders().set(SysConstatnt.TRACE_ID, finalTraceIdVal);
                    log.info("回写traceId:{}", finalTraceIdVal);
                }
                super.beforeCommit(action);
            }
        }).build();*/
        return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable( () -> {
            if(!response.getHeaders().containsKey(SysConstatnt.TRACE_ID)) {
                response.getHeaders().set(SysConstatnt.TRACE_ID, finalTraceIdVal);
                log.info("回写traceId:{}", finalTraceIdVal);
            }
            // 处理调用结果，用于判断api质量
            log.info("接口调用结果：{}",response.getStatusCode());
        }));
    }

    @Override
    public int getOrder() {
        return SysConstatnt.FilterOrder.FILTER_TRACE;
    }
}
